// ****************************************************************************

// ****************************************************************************

#include "UDP_Observer.hpp"

#include <sstream>
#include "GenSocketManager.hpp"
#include "GenUDP_Connection.hpp"
#include "UtCast.hpp"
#include "UtInputBlock.hpp"
#include "UtLog.hpp"
#include "RegisterUDP_Observer.hpp"
#include "UDPObserverPrivate.hpp"


#include "UDPObserverPrivate.hpp"
#include "GenUDP_Connection.hpp"

UDP_ObserverPrivate::UDP_ObserverPrivate(UtCallbackHolder& callBackes, GenUDP_Connection* conn)
{
	mControlInterface = new ObserverControlInterface();
	mEventInterface = new ObserverEventInterface(callBackes, conn);
	mSituationInterface = new ObserverSituationInterface(callBackes, conn);
}

UDP_ObserverPrivate& UDP_ObserverPrivate::operator=(const UDP_ObserverPrivate& aSrc)
{
	mControlInterface = aSrc.mControlInterface;
	mEventInterface = aSrc.mEventInterface;
	mSituationInterface = aSrc.mSituationInterface;
	return  *this;
}

UDP_ObserverPrivate::~UDP_ObserverPrivate()
{
	delete mControlInterface;
	delete mEventInterface;
	delete mSituationInterface;
}

using InterfaceError = ObserverControlInterface::InterfaceError;
static bool isInitPlatFormSides = false;

UDP_Observer::UDP_Observer()
	: mPort(14421),
	  mRecvPort(14422),
	  mAddress(),
	  mConnectionPtr(nullptr)
{
	mData = new UDP_ObserverPrivate(mCallbacks, mConnectionPtr);
}
UDP_Observer::UDP_Observer(const UDP_Observer &aSrc)
	: mPort(aSrc.mPort),
	  mRecvPort(aSrc.mRecvPort),
	  mAddress(aSrc.mAddress),
	  mConnectionPtr(nullptr)
{
	mData = new UDP_ObserverPrivate(mCallbacks, mConnectionPtr);
}
UDP_Observer &UDP_Observer::operator=(const UDP_Observer &aSrc)
{
	mPort = aSrc.mPort;
	mRecvPort = aSrc.mRecvPort;
	mAddress = aSrc.mAddress;
	mConnectionPtr = nullptr;
	mData = aSrc.mData;
	return *this;
}
UDP_Observer::~UDP_Observer() noexcept
{
	Disconnect();
}

bool UDP_Observer::Initialize()
{
	if (mAddress.empty())
	{
		Disconnect();
		return true;
	}
	bool connected = false;

	mConnectionPtr = new GenUDP_Connection();
	connected = mConnectionPtr->Init(mAddress, mPort, mRecvPort);

	if (connected)
	{
		// 启动数据接收线程
		std::thread t([&]()
					  {
            while (this->mConnectionPtr)
            {
                char aBuffer[1024];
                memset(aBuffer, '\0', 1024);

                int bytes = mConnectionPtr->ReceiveBuffer(3000, aBuffer, 1024);

                if (bytes > 0)
                {
					InterfaceError result = mData->mControlInterface->DecodeMsg(std::string(aBuffer));
					SendPacket(result.errorInfo);
                }
            } });

		t.detach();
	}
	else
	{
		auto out = ut::log::error() << "Could not connect to socket.";
		out.AddNote() << "Address: " << mAddress;
		out.AddNote() << "Port: " << mPort;

		delete mConnectionPtr;
		mConnectionPtr = nullptr;
	}
	return connected;
}
bool UDP_Observer::ProcessInput(UtInput &aInput)
{
	bool myCommand = false;

	if (aInput.GetCommand() == "udp_observer")
	{
		myCommand = true;

		UtInputBlock block(aInput);

		std::string command;
		while (block.ReadCommand(command))
		{
			if (command == "port")
			{
				aInput.ReadValue(mPort);

				mRecvPort = mPort + 1; // 自动设置接收端口号
			}
			else if (command == "address")
			{
				aInput.ReadValue(mAddress);
			}
			else
			{
				throw UtInput::UnknownCommand(aInput);
			}
		}
	}
	return myCommand;
}
void UDP_Observer::Disconnect()
{
	delete mConnectionPtr;
	mConnectionPtr = nullptr;
	mCallbacks.Clear();
}
void UDP_Observer::initPlatformSides()
{
	mPlatformSides.clear();
	size_t platFormCount = GetSimulation().GetPlatformCount();
	mPlatformSides.reserve(platFormCount);
	for (size_t i = 1; i <= platFormCount; i++)
	{
		WsfPlatform *curPlatForm = GetSimulation().GetPlatformByIndex(i);
		if (!curPlatForm)
			continue;

		std::string side = curPlatForm->GetSide();
		mPlatformSides.emplace_back(static_cast<int>(i), side);
	}
}
void UDP_Observer::SendPacket(const std::string &aMessage)
{
	int bytesWritten = mConnectionPtr->SendBuffer(aMessage.c_str(), ut::cast_to_int(aMessage.length() + 1));
	if (bytesWritten < 0)
	{
		ut::log::error() << "Socket error: " << GenSockets::GenSocketManager::GetLastError();
		Disconnect();
	}
}